#lang racket


(require "global.rkt"
         (prefix-in backends: "backends/main.rkt")
         (prefix-in ac: "autocad/main.rkt")
         (prefix-in rh: "rhinoceros3d/main.rkt"))

(provide (all-from-out "autocad/main.rkt"
                       "rhinoceros3d/main.rkt"))

(provide autocad
         rhino
         backend
;         backend-in
;         backend-out
         
;         with-backend
;         with-backend-in
;         with-backend-out
         )


(define backend-manager (make-hasheq))

(define (add-backend-manager! proxy-fn backend)
  (hash-set! backend-manager proxy-fn backend))

(define (member-backend-manager? proxy-fn)
  (hash-has-key? backend-manager proxy-fn))

(define (get-backend-manager proxy-fn)
  (hash-ref backend-manager proxy-fn))


(define autocad ac:load-autocad-proxy)
(define rhino rh:load-rhino-proxy)


(define (ensure-backend proxy-fn)
  (if (member-backend-manager? proxy-fn)
      (get-backend-manager proxy-fn)
      (let ((backend (backends:make-backend (proxy-fn))))
        (add-backend-manager! proxy-fn backend)
        backend)))


(define (backend proxy-fn)
  (unless (procedure? proxy-fn)
    (error 'backend-fn "Available backends are autocad and rhino"))
  (let ((backend (ensure-backend proxy-fn)))
    (set-current-in-backend! backend)
    (set-current-out-backend! backend)
    (backends:begin-session! backend)
    backend))

;(define (backend-in cad)
;  (backend-fn
;   cad
;   (λ () (set-current-in-backend! (ensure-autocad-backend)))
;   (λ () (set-current-in-backend! (ensure-rhino-backend)))))
;
;(define (backend-out cad)
;  (backend-fn
;   cad
;   (λ () (set-current-out-backend! (ensure-autocad-backend)))
;   (λ () (set-current-out-backend! (ensure-rhino-backend)))))
;
;
;(define (ensure-backend cad)
;  (backend-fn
;   cad
;   (λ () (ensure-autocad-backend))
;   (λ () (ensure-rhino-backend))))
;
;(define-syntax with-backend
;  (syntax-rules ()
;    ((_ cad body ...)
;     (parameterize ((current-in-backend (ensure-backend cad))
;                    (current-out-backend (ensure-backend cad)))
;       body ...))))
;
;(define-syntax with-backend-in
;  (syntax-rules ()
;    ((_ cad body ...)
;     (parameterize ((current-in-backend (ensure-backend cad)))
;       body ...))))
;
;(define-syntax with-backend-out
;  (syntax-rules ()
;    ((_ cad body ...)
;     (parameterize ((current-out-backend (ensure-backend cad)))
;       body ...))))